home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / ARP.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  11KB  |  400 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "enet.h"
  9. #include "ax25.h"
  10. #include "icmp.h"
  11. #include "ip.h"
  12. #include "arp.h"
  13. #include "icmp.h"
  14.  
  15. static unsigned arp_hash __ARGS((int16 hardware,int32 ipaddr));
  16. static void arp_output __ARGS((struct iface *iface,int16 hardware,int32 target));
  17.  
  18. /* ARP entries for particular subnetwork types. The table values
  19.  * are filled in by calls to arp_init() at device attach time
  20.  */
  21. #define    NTYPES    9
  22. struct arp_type Arp_type[NTYPES];
  23.  
  24. /* Hash table headers */
  25. struct arp_tab *Arp_tab[ARPSIZE];
  26.  
  27. struct arp_stat Arp_stat;
  28.  
  29. /* Initialize an entry in the ARP table
  30.  * Called by the device driver at attach time
  31.  */
  32. int
  33. arp_init(hwtype,hwalen,iptype,arptype,pendtime,bdcst,format,scan)
  34. unsigned int hwtype;    /* ARP Hardware type */
  35. int hwalen;        /* Hardware address length */
  36. int iptype;        /* Subnet's protocol ID for IP */
  37. int arptype;        /* Subnet's protocol ID for ARP */
  38. int pendtime;        /* # secs to wait pending response */
  39. char *bdcst;        /* Subnet's broadcast address (if any) */
  40. int (*format)();    /* Function to format hardware addresses */
  41. int (*scan)();        /* Function to scan addresses in ascii */    
  42. {
  43.     register struct arp_type *at;
  44.  
  45.     if(hwtype >= NTYPES)
  46.         return -1;    /* Table too small */
  47.  
  48.     at = &Arp_type[hwtype];
  49.     at->hwalen = (int16)hwalen;
  50.     at->iptype = (int16)iptype;
  51.     at->arptype = (int16)arptype;
  52.     at->pendtime = (int16)pendtime;
  53.     at->bdcst = bdcst;
  54.     at->format = format;
  55.     at->scan = scan;
  56.     return 0;
  57. }
  58.  
  59. /* Resolve an IP address to a hardware address; if not found,
  60.  * initiate query and return NULLCHAR.  If an address is returned, the
  61.  * interface driver may send the packet; if NULLCHAR is returned,
  62.  * res_arp() will have saved the packet on its pending queue,
  63.  * so no further action (like freeing the packet) is necessary.
  64.  */
  65. char *
  66. res_arp(iface,hardware,target,bp)
  67. struct iface *iface;    /* Pointer to interface block */
  68. int16 hardware;        /* Hardware type */
  69. int32 target;        /* Target IP address */
  70. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  71. {
  72.     register struct arp_tab *arp;
  73.     struct ip ip;
  74.  
  75.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  76.         return arp->hw_addr;
  77.     if(arp != NULLARP){
  78.         /* Earlier packets are already pending, kick this one back
  79.          * as a source quench
  80.          */
  81.         ntohip(&ip,&bp);
  82.         icmp_output(&ip,bp,QUENCH,0,NULL);
  83.         free_p(bp);
  84.     } else {
  85.         /* Create an entry and put the datagram on the
  86.          * queue pending an answer
  87.          */
  88.         arp = arp_add(target,hardware,NULLCHAR,0,0);
  89.         enqueue(&arp->pending,bp);
  90.         arp_output(iface,hardware,target);
  91.     }
  92.     return NULLCHAR;
  93. }
  94. /* Handle incoming ARP packets. This is almost a direct implementation of
  95.  * the algorithm on page 5 of RFC 826, except for:
  96.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  97.  *    pending a reply to our ARP request.
  98.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  99.  * 3. Requests for IP addresses listed in our table as "published" are
  100.  *    responded to, even if the address is not our own.
  101.  */
  102. void
  103. arp_input(iface,bp)
  104. struct iface *iface;
  105. struct mbuf *bp;
  106. {
  107.     struct arp arp;
  108.     struct arp_tab *ap;
  109.     struct arp_type *at;
  110.     
  111.     Arp_stat.recv++;
  112.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  113.         return;
  114.     if(arp.hardware >= NTYPES){
  115.         /* Unknown hardware type, ignore */
  116.         Arp_stat.badtype++;
  117.         return;
  118.     }
  119.     at = &Arp_type[arp.hardware];
  120.     if(arp.protocol != at->iptype){
  121.         /* Unsupported protocol type, ignore */
  122.         Arp_stat.badtype++;
  123.         return;
  124.     }
  125.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  126.         /* Incorrect protocol addr length (different hw addr lengths
  127.          * are OK since AX.25 addresses can be of variable length)
  128.          */
  129.         Arp_stat.badlen++;
  130.         return;
  131.     }
  132.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  133.         /* This guy is trying to say he's got the broadcast address! */
  134.         Arp_stat.badaddr++;
  135.         return;
  136.     }
  137.     /* If this guy is already in the table, update its entry
  138.      * unless it's a manual entry (noted by the lack of a timer)
  139.      */
  140.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  141.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  142.      && ap->timer.start != 0){
  143.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  144.     }
  145.     /* See if we're the address they're looking for */
  146.     if(arp.tprotaddr == Ip_addr){
  147.         if(ap == NULLARP)    /* Only if not already in the table */
  148.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  149.  
  150.         if(arp.opcode == ARP_REQUEST){
  151.             /* Swap sender's and target's (us) hardware and protocol
  152.              * fields, and send the packet back as a reply
  153.              */
  154.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  155.             /* Mark the end of the sender's AX.25 address
  156.              * in case he didn't
  157.              */
  158.             if(arp.hardware == ARP_AX25)
  159.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  160.  
  161.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  162.             arp.tprotaddr = arp.sprotaddr;
  163.             arp.sprotaddr = Ip_addr;
  164.             arp.opcode = ARP_REPLY;
  165.             if((bp = htonarp(&arp)) == NULLBUF)
  166.                 return;
  167.  
  168.             if(iface->forw != NULLIF)
  169.                 (*iface->forw->output)(iface->forw,
  170.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  171.             else 
  172.                 (*iface->output)(iface,arp.thwaddr,
  173.                  iface->hwaddr,at->arptype,bp);
  174.             Arp_stat.inreq++;
  175.         } else {
  176.             Arp_stat.replies++;
  177.         }
  178.     } else if(arp.opcode == ARP_REQUEST
  179.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  180.         && ap->pub){
  181.         /* Otherwise, respond if the guy he's looking for is
  182.          * published in our table.
  183.          */
  184.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  185.         /* Mark the end of the sender's AX.25 address
  186.          * in case he didn't
  187.          */
  188.         if(arp.hardware == ARP_AX25)
  189.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  190.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  191.         arp.tprotaddr = arp.sprotaddr;
  192.         arp.sprotaddr = ap->ip_addr;
  193.         arp.opcode = ARP_REPLY;
  194.         if((bp = htonarp(&arp)) == NULLBUF)
  195.             return;
  196.         if(iface->forw != NULLIF)
  197.             (*iface->forw->output)(iface->forw,
  198.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  199.         else 
  200.             (*iface->output)(iface,arp.thwaddr,
  201.              iface->hwaddr,at->arptype,bp);
  202.         Arp_stat.inreq++;
  203.     }
  204. }
  205. /* Add an IP-addr / hardware-addr pair to the ARP table */
  206. struct arp_tab *
  207. arp_add(ipaddr,hardware,hw_addr,hw_alen,pub)
  208. int32 ipaddr;        /* IP address, host order */
  209. int16 hardware;        /* Hardware type */
  210. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  211. int16 hw_alen;        /* Length of hardware address */
  212. int pub;        /* Publish this entry? */
  213. {
  214.     struct mbuf *bp;
  215.     register struct arp_tab *ap;
  216.     unsigned hashval;
  217.  
  218.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  219.         /* New entry */
  220.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  221.             return NULLARP;
  222.         ap->timer.func = arp_drop;
  223.         ap->timer.arg = ap;
  224.         ap->hardware = hardware;
  225.         ap->ip_addr = ipaddr;
  226.  
  227.         /* Put on head of hash chain */
  228.         hashval = arp_hash(hardware,ipaddr);
  229.         ap->prev = NULLARP;
  230.         ap->next = Arp_tab[hashval];
  231.         Arp_tab[hashval] = ap;
  232.         if(ap->next != NULLARP){
  233.             ap->next->prev = ap;
  234.         }
  235.     }
  236.     if(hw_addr == NULLCHAR){
  237.         /* Await response */
  238.         ap->state = ARP_PENDING;
  239.         ap->timer.start = Arp_type[hardware].pendtime * (1000 / MSPTICK);
  240.     } else {
  241.         /* Response has come in, update entry and run through queue */
  242.         ap->state = ARP_VALID;
  243.         ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  244.         free(ap->hw_addr);
  245.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  246.             free(ap);
  247.             return NULLARP;
  248.         }
  249.         memcpy(ap->hw_addr,hw_addr,hw_alen);
  250.         /* This kludge marks the end of an AX.25 address to allow
  251.          * for optional digipeaters (insert Joan Rivers salute here)
  252.          */
  253.         if(hardware == ARP_AX25)
  254.             ap->hw_addr[hw_alen-1] |= E;
  255.         ap->pub = pub;
  256.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  257.             ip_route(bp,0);
  258.     }
  259.     start_timer(&ap->timer);
  260.     return ap;
  261. }
  262.  
  263. /* Remove an entry from the ARP table */
  264. void
  265. arp_drop(p)
  266. void *p;
  267.  
  268. {
  269.     register struct arp_tab *ap;
  270.  
  271.     ap = (struct arp_tab *)p;
  272.     if(ap == NULLARP)
  273.         return;
  274.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  275.     if(ap->next != NULLARP)
  276.         ap->next->prev = ap->prev;
  277.     if(ap->prev != NULLARP)
  278.         ap->prev->next = ap->next;
  279.     else
  280.         Arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  281.     free(ap->hw_addr);
  282.     free_q(&ap->pending);
  283.     free((char *)ap);
  284. }
  285.  
  286. /* Look up the given IP address in the ARP table */
  287. struct arp_tab *
  288. arp_lookup(hardware,ipaddr)
  289. int16 hardware;
  290. int32 ipaddr;
  291. {
  292.     register struct arp_tab *ap;
  293.  
  294.     for(ap = Arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  295.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  296.             break;
  297.     }
  298.     return ap;
  299. }
  300. /* Send an ARP request to resolve IP address target_ip */
  301. static void
  302. arp_output(iface,hardware,target)
  303. struct iface *iface;
  304. int16 hardware;
  305. int32 target;
  306. {
  307.     struct arp arp;
  308.     struct mbuf *bp;
  309.     struct arp_type *at;
  310.  
  311.     at = &Arp_type[hardware];
  312.     if(iface->output == NULLFP)
  313.         return;
  314.     
  315.     arp.hardware = hardware;
  316.     arp.protocol = at->iptype;
  317.     arp.hwalen = at->hwalen;
  318.     arp.pralen = sizeof(int32);
  319.     arp.opcode = ARP_REQUEST;
  320.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  321.     arp.sprotaddr = Ip_addr;
  322.     memset(arp.thwaddr,0,at->hwalen);
  323.     arp.tprotaddr = target;
  324.     if((bp = htonarp(&arp)) == NULLBUF)
  325.         return;
  326.     (*iface->output)(iface,at->bdcst,
  327.         iface->hwaddr,at->arptype,bp);
  328.     Arp_stat.outreq++;
  329. }
  330.  
  331. /* Hash a {hardware type, IP address} pair */
  332. static
  333. unsigned
  334. arp_hash(hardware,ipaddr)
  335. int16 hardware;
  336. int32 ipaddr;
  337. {
  338.     register unsigned hashval;
  339.  
  340.     hashval = hardware;
  341.     hashval ^= hiword(ipaddr);
  342.     hashval ^= loword(ipaddr);
  343.     return hashval % ARPSIZE;
  344. }        
  345. /* Copy a host format arp structure into mbuf for transmission */
  346. struct mbuf *
  347. htonarp(arp)
  348. register struct arp *arp;
  349. {
  350.     struct mbuf *bp;
  351.     register char *buf;
  352.  
  353.     if(arp == (struct arp *)NULL)
  354.         return NULLBUF;
  355.     if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  356.         return NULLBUF;
  357.  
  358.     buf = bp->data;
  359.  
  360.     buf = put16(buf,arp->hardware);
  361.     buf = put16(buf,arp->protocol);
  362.     *buf++ = arp->hwalen;
  363.     *buf++ = arp->pralen;
  364.     buf = put16(buf,arp->opcode);
  365.     memcpy(buf,arp->shwaddr,(int16)uchar(arp->hwalen));
  366.     buf += arp->hwalen;
  367.     buf = put32(buf,arp->sprotaddr);
  368.     memcpy(buf,arp->thwaddr,(int16)uchar(arp->hwalen));
  369.     buf += arp->hwalen;
  370.     buf = put32(buf,arp->tprotaddr);
  371.  
  372.     bp->cnt = buf - bp->data;
  373.     return bp;
  374. }
  375. /* Convert an incoming ARP packet into a host-format structure */
  376. int
  377. ntoharp(arp,bpp)
  378. register struct arp *arp;
  379. struct mbuf **bpp;
  380. {
  381.     if(arp == (struct arp *)NULL || bpp == NULLBUFP)
  382.         return -1;
  383.  
  384.     arp->hardware = pull16(bpp);
  385.     arp->protocol = pull16(bpp);
  386.     arp->hwalen = pullchar(bpp);
  387.     arp->pralen = pullchar(bpp);
  388.     arp->opcode = pull16(bpp);
  389.     pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  390.     arp->sprotaddr = pull32(bpp);
  391.     pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  392.  
  393.     arp->tprotaddr = pull32(bpp);
  394.  
  395.     /* Get rid of anything left over */
  396.     free_p(*bpp);
  397.     *bpp = NULLBUF;
  398.     return 0;
  399. }
  400.